home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / internet / blat15i.zip / BLAT.CPP < prev    next >
C/C++ Source or Header  |  1996-03-28  |  30KB  |  1,111 lines

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <iostream.h>
  5. /* generic socket DLL support */
  6. #include "gensock.h"
  7.  
  8. #ifdef WIN32         
  9.   #define __far far
  10.   #define huge far
  11.   #define __near near
  12. #endif               
  13.  
  14. #define MAXOUTLINE 255
  15.  
  16. HANDLE    gensock_lib = 0;
  17.  
  18. int (FAR PASCAL *pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
  19. int (FAR PASCAL *pgensock_getchar) (socktag st, int wait, char FAR * ch);
  20. int (FAR PASCAL *pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
  21. int (FAR PASCAL *pgensock_close) (socktag st);
  22. int (FAR PASCAL *pgensock_gethostname) (char FAR * name, int namelen);
  23. int (FAR PASCAL *pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
  24. int (FAR PASCAL *pgensock_put_data_flush) (socktag st);
  25.  
  26.  
  27. socktag SMTPSock;
  28. #define SERVER_SIZE    256     // #defines (bleah!) from Beverly Brown "beverly@datacube.com"
  29. #define SENDER_SIZE    256
  30. char SMTPHost[SERVER_SIZE];
  31. char Sender[SENDER_SIZE];
  32. char *Recipients;
  33. char my_hostname[1024];
  34. char *destination="";
  35. char *cc_list="";
  36. char *bcc_list="";
  37. char *loginname="";
  38. char *senderid="";
  39. char *subject="";
  40. int mime=0;
  41. int quiet=0;
  42.  
  43. char *usage[]=
  44. {
  45.  "Blat v1.5: WinNT console utility to mail a file via SMTP",
  46.  "",
  47.  "syntax:",
  48.  "Blat <filename> -t <recipient> [optional switches (see below)]",
  49.  "Blat -install <server addr> <sender's addr> [-q]",
  50.  "Blat -h [-q]",
  51.  "",
  52.  "-install <server addr> <sender's addr>: set's default SMTP server and sender",
  53.  "",
  54.  "<filename>    : file with the message body ('-' for console input, end with ^Z)",
  55.  "-t <recipient>: recipient list (comma separated)",
  56.  "-s <subj>     : subject line",
  57.  "-f <sender>   : overrides the default sender address (must be known to server)",
  58.  "-i <addr>     : a 'From:' address, not necessarily known to the SMTP server.",
  59.  "-c <recipient>: carbon copy recipient list (comma separated)",
  60.  "-b <recipient>: blind carbon copy recipient list (comma separated)",
  61.  "-h            : displays this help.",
  62.  "-mime         : MIME Quoted-Printable Content-Transfer-Encoding.",
  63.  "-q            : supresses *all* output.",
  64.  "-server <addr>: overrides the default SMTP server to be used.",
  65.  "",
  66.  "Note that if the '-i' option is used, <sender> is included in 'Reply-to:'",
  67.  "and 'Sender:' fields in the header of the message."
  68. };
  69. const NMLINES=22;
  70.  
  71. void
  72. gensock_error (char * function, int retval)
  73. {
  74.  if( ! quiet )
  75.  {
  76.   switch( retval )
  77.   {
  78.    case 4001: cout<< "Error: Malloc failed (possibly out of memory)."; break;
  79.    case 4002: cout<< "Error: Error sending data."; break;
  80.    case 4003: cout<< "Error: Error initializing gensock.dll."; break;
  81.    case 4004: cout<< "Error: Version not supported."; break;
  82.    case 4005: cout<< "Error: The winsock version specified by gensock is not supported by this winsock.dll."; break;
  83.    case 4006: cout<< "Error: Network not ready."; break;
  84.    case 4007: cout<< "Error: Can't resolve (mailserver) hostname."; break;
  85.    case 4008: cout<< "Error: Can't create a socket (too many simultaneous links?)"; break;
  86.    case 4009: cout<< "Error: Error reading socket."; break;
  87.    case 4010: cout<< "Error: Not a socket."; break;
  88.    case 4011: cout<< "Error: Busy."; break;
  89.    case 4012: cout<< "Error: Error closing socket."; break;
  90.    case 4013: cout<< "Error: Wait a bit (possible timeout)."; break;
  91.    case 4014: cout<< "Error: Can't resolve service."; break;
  92.    case 4015: cout<< "Error: Can't connect to mailserver (timed out if winsock.dll error 10060)"; break;
  93.    case 4016: cout<< "Error: Connection to mailserver was dropped."; break;
  94.    case 4017: cout<< "Error: Mail server refused connection."; break;
  95.    default: cout << "error " << retval << " in function '" << function;
  96.   }
  97.  }
  98. }
  99.  
  100. // loads the GENSOCK DLL file
  101. int load_gensock()
  102. {
  103.   if( (gensock_lib = LoadLibrary("gwinsock.dll")) == NULL )
  104.   {
  105.    if( (gensock_lib = LoadLibrary("gensock.dll")) == NULL )
  106.    {
  107.     if( ! quiet )
  108.      cout << "Couldn't load either 'GWINSOCK.DLL' or 'GENSOCK.DLL'\nInstall one of these in your path.";
  109.     return -1;
  110.    }
  111.   }
  112.  
  113.   if( 
  114.      ( pgensock_connect = 
  115.       (  int (FAR PASCAL *)(char FAR *, char FAR *, socktag FAR *) )
  116.       GetProcAddress(gensock_lib, "gensock_connect")
  117.      ) == NULL
  118.     )
  119.   {
  120.    if( ! quiet )
  121.     cout << "couldn't getprocaddress for gensock_connect\n";
  122.    return -1;
  123.   }
  124.  
  125.   if (
  126.       ( pgensock_getchar =
  127.        ( int (FAR PASCAL *) (socktag, int, char FAR *) )
  128.        GetProcAddress(gensock_lib, "gensock_getchar")
  129.       ) == NULL
  130.      )
  131.   {
  132.    if( ! quiet )
  133.     cout << "couldn't getprocaddress for gensock_getchar\n";
  134.    return -1;
  135.   }
  136.  
  137.   if(
  138.      ( pgensock_put_data =
  139.        ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
  140.        GetProcAddress(gensock_lib, "gensock_put_data")
  141.      ) == NULL
  142.     )
  143.   {
  144.    if( ! quiet )
  145.     cout << "couldn't getprocaddress for gensock_put_data\n";
  146.    return -1;
  147.   }
  148.  
  149.   if(
  150.      ( pgensock_close =
  151.        (int (FAR PASCAL *) (socktag) )
  152.        GetProcAddress(gensock_lib, "gensock_close")
  153.      ) == NULL
  154.     )
  155.   {
  156.    if( ! quiet )
  157.     cout << "couldn't getprocaddress for gensock_close\n";
  158.    return -1;
  159.   }
  160.  
  161.   if(
  162.      ( pgensock_gethostname =
  163.        (int (FAR PASCAL *) (char FAR *, int) )       
  164.        GetProcAddress(gensock_lib, "gensock_gethostname")
  165.      ) == NULL
  166.     )
  167.   {
  168.    if( ! quiet )
  169.     cout << "couldn't getprocaddress for gensock_gethostname\n";
  170.    return -1;
  171.   }
  172.  
  173.   if(
  174.      ( pgensock_put_data_buffered =
  175.        ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
  176.        GetProcAddress(gensock_lib, "gensock_put_data_buffered")
  177.      ) == NULL
  178.     )
  179.   {
  180.    if( ! quiet )
  181.     cout << "couldn't getprocaddress for gensock_put_data_buffered\n";
  182.    return -1;
  183.   }
  184.  
  185.   if(
  186.      ( pgensock_put_data_flush =
  187.        ( int (FAR PASCAL *) (socktag) )
  188.        GetProcAddress(gensock_lib, "gensock_put_data_flush")
  189.      ) == NULL
  190.     )
  191.   {
  192.    if( ! quiet )
  193.     cout << "couldn't getprocaddress for gensock_put_data_flush\n";
  194.    return -1;
  195.   }
  196.  
  197.   return 0;
  198. }
  199.  
  200. int open_smtp_socket( void )
  201. {
  202.   int retval;
  203.  
  204.   /* load the library if it's not loaded */
  205. //  if (!gensock_lib)
  206.     if ( ( retval = load_gensock() ) ) return ( retval );
  207.  
  208.   if ( (retval = (*pgensock_connect) ((LPSTR) SMTPHost,
  209.                      (LPSTR)"smtp",
  210.                      &SMTPSock)))
  211.   {
  212.     if (retval == ERR_CANT_RESOLVE_SERVICE)
  213.     {
  214.      if ((retval = (*pgensock_connect) ((LPSTR)SMTPHost,
  215.                      (LPSTR)"25",
  216.                      &SMTPSock)))
  217.      {
  218.        gensock_error ("gensock_connect", retval);
  219.        return -1;
  220.      }
  221.     }
  222.   // error other than can't resolve service 
  223.     else
  224.     {
  225.      gensock_error ("gensock_connect", retval);
  226.      return -1;
  227.     }
  228.   }
  229.  
  230.   // we wait to do this until here because WINSOCK is
  231.   // guaranteed to be already initialized at this point.
  232.  
  233.   // get the local hostname (needed by SMTP) 
  234.   if ((retval = (*pgensock_gethostname) (my_hostname, sizeof(my_hostname))))
  235.   {
  236.     gensock_error ("gensock_gethostname", retval);
  237.     return -1;
  238.   }
  239.   return 0;
  240. }
  241.  
  242.  
  243. int close_smtp_socket( void )
  244. {
  245.   int retval;
  246.  
  247.   if( (retval = (*pgensock_close) (SMTPSock)) )
  248.   {
  249.     gensock_error ("gensock_close", retval);
  250.     return -1;
  251.   }
  252.   FreeLibrary( gensock_lib );
  253.   return (0);
  254. }
  255.  
  256. int get_smtp_line( void )
  257. {
  258.   char ch = '.';
  259.   char in_data [MAXOUTLINE];
  260.   char * index;
  261.   int retval = 0;
  262.  
  263.   index = in_data;
  264.  
  265.   while (ch != '\n')
  266.   {
  267.    if( (retval = (*pgensock_getchar) (SMTPSock, 0, &ch) ) )
  268.    {
  269.       gensock_error ("gensock_getchar", retval);
  270.       return -1;
  271.     }
  272.     else
  273.     {
  274.       *index = ch;
  275.       index++;
  276.     }
  277.   }
  278.  
  279.   /* this is to support multi-line responses, common with */
  280.   /* servers that speak ESMTP */
  281.  
  282.   /* I know, I know, it's a hack 8^) */
  283.   if( in_data[3] == '-' ) return( get_smtp_line() );
  284.   else return atoi(in_data);
  285. }
  286.  
  287. int put_smtp_line( socktag sock, char far * line, unsigned int nchars )
  288. {
  289.   int retval;
  290.  
  291.   if( (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars)))
  292.   {
  293.     gensock_error ("gensock_put_data", retval);
  294.     return -1;
  295.   }
  296.   return (0);
  297. }
  298.  
  299. int putline_internal (socktag sock, char * line, unsigned int nchars)
  300. {
  301.   int retval;
  302.  
  303.   if ((retval =
  304.        (*pgensock_put_data) (sock,
  305.                 (char FAR *) line,
  306.                 (unsigned long) nchars)))
  307.   {
  308.     switch (retval)
  309.     {
  310.      case ERR_NOT_CONNECTED:
  311.       gensock_error( "SMTP server has closed the connection", retval );
  312.       break;
  313.  
  314.      default:
  315.       gensock_error ("gensock_put_data", retval);
  316.     }
  317.     return -1;
  318.   }
  319.   return (0);
  320. }
  321.  
  322. void smtp_error (char * message)
  323. {
  324.  if( ! quiet )
  325.   cout << message << "\n";
  326.  put_smtp_line (SMTPSock, "QUIT\r\n", 6);
  327.  close_smtp_socket();
  328. }
  329.  
  330.  
  331. // 'destination' is the address the message is to be sent to
  332. // 'message' is a pointer to a null-terminated 'string' containing the 
  333. // entire text of the message. 
  334.  
  335. int prepare_smtp_message(char * MailAddress, char * destination)
  336. {
  337.   char out_data[MAXOUTLINE];
  338.   char str[1024];
  339.   char *ptr;
  340.   int len, startLen;
  341.  
  342.   if ( open_smtp_socket() ) return -1;
  343.  
  344.   if ( get_smtp_line() != 220 )
  345.   {
  346.     smtp_error ("SMTP server error");
  347.     return(-1);
  348.   }
  349.  
  350.   sprintf( out_data, "HELO %s\r\n", my_hostname );
  351.   put_smtp_line( SMTPSock, out_data, strlen (out_data) );
  352.  
  353.   if ( get_smtp_line() != 250 )
  354.   {
  355.     smtp_error ("SMTP server error");
  356.     return -1;
  357.   }
  358.  
  359.   sprintf (out_data, "MAIL From:<%s>\r\n", loginname);
  360.   put_smtp_line( SMTPSock, out_data, strlen (out_data) );
  361.  
  362.   if (get_smtp_line() != 250)
  363.   {
  364.     smtp_error ("The mail server doesn't like the sender name,\nhave you set your mail address correctly?");
  365.     return -1;
  366.   }
  367.  
  368.   // do a series of RCPT lines for each name in address line
  369.   for (ptr = destination; *ptr; ptr += len + 1)
  370.   {
  371.     // if there's only one token left, then len will = startLen,
  372.     // and we'll iterate once only
  373.     startLen = strlen (ptr);
  374.     if ((len = strcspn (ptr, " ,\n\t\r")) != startLen)
  375.     {
  376.       ptr[len] = '\0';            // replace delim with NULL char
  377.       while (strchr (" ,\n\t\r", ptr[len+1]))    // eat white space
  378.         ptr[len++] = '\0';
  379.     }
  380.  
  381.     sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
  382.     putline_internal( SMTPSock, out_data, strlen (out_data) );
  383.  
  384.     if (get_smtp_line() != 250)
  385.     {
  386.       sprintf (str, "The mail server doesn't like the name %s.\nHave you set the 'To: ' field correctly?", ptr);
  387.       smtp_error (str);
  388.       return -1;
  389.     }
  390.  
  391.     if (len == startLen)    // last token, we're done
  392.       break;
  393.   }
  394.  
  395.   sprintf (out_data, "DATA\r\n");
  396.   put_smtp_line (SMTPSock, out_data, strlen (out_data));
  397.  
  398.   if (get_smtp_line() != 354)
  399.   {
  400.     smtp_error ("Mail server error accepting message data");
  401.     return -1;
  402.   }
  403.  
  404.   return(0);
  405.  
  406. }
  407.  
  408. int transform_and_send_edit_data( socktag sock, char * editptr )
  409. {
  410.   char *index;
  411.   char *header_end;
  412.   char previous_char = 'x';
  413.   unsigned int send_len;
  414.   int retval;
  415.   BOOL done = 0;
  416.  
  417.   send_len = lstrlen(editptr);
  418.   index = editptr;
  419.  
  420.   header_end = strstr (editptr, "\r\n\r\n");
  421.  
  422.   while (!done)
  423.   {
  424.     // room for extra char for double dot on end case
  425.     while ((unsigned int) (index - editptr) < send_len)
  426.     {
  427.       switch (*index)
  428.       {
  429.        case '.':
  430.                  if (previous_char == '\n')
  431.                   /* send _two_ dots... */
  432.                   if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) return (retval);
  433.                    if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) return (retval);
  434.                  break;
  435.        case '\r':
  436.                  // watch for soft-breaks in the header, and ignore them
  437.                  if (index < header_end && (strncmp (index, "\r\r\n", 3) == 0))
  438.                    index += 2;
  439.                  else
  440.                   if (previous_char != '\r')
  441.                    if ((retval = (*pgensock_put_data_buffered) (sock, index, 1)))
  442.                     return (retval);
  443.                   // soft line-break (see EM_FMTLINES), skip extra CR */
  444.                  break;
  445.        default:
  446.                if ((retval = (*pgensock_put_data_buffered) (sock, index, 1)))
  447.                 return (retval);
  448.       }
  449.       previous_char = *index;
  450.       index++;
  451.     }
  452.     if( (unsigned int) (index - editptr) == send_len) done = 1;
  453.   }
  454.  
  455.   // this handles the case where the user doesn't end the last
  456.   // line with a <return>
  457.  
  458.   if (editptr[send_len-1] != '\n')
  459.   {
  460.     if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n.\r\n", 5)))
  461.       return (retval);
  462.   }
  463.   else
  464.     if ((retval = (*pgensock_put_data_buffered) (sock, ".\r\n", 3)))
  465.       return (retval);
  466.  
  467.   /* now make sure it's all sent... */
  468.   if ((retval = (*pgensock_put_data_flush)(sock))) return (retval);
  469.   return (TRUE);
  470. }
  471.  
  472.  
  473.  
  474. int send_smtp_edit_data (char * message)
  475. {
  476.   transform_and_send_edit_data( SMTPSock, message );
  477.  
  478.   if (get_smtp_line() != 250)
  479.   {
  480.     smtp_error ("Message not accepted by server");
  481.     return -1;
  482.   }
  483.   return(0);
  484. }
  485.  
  486.  
  487. int finish_smtp_message( void )
  488. {
  489.   return put_smtp_line( SMTPSock, "QUIT\r\n", 6 );
  490. }
  491.  
  492. // create a registry entries for this program 
  493. int CreateRegEntry( void )
  494. {
  495.   HKEY  hKey1;
  496.   DWORD  dwDisposition;
  497.   LONG   lRetCode;
  498.  
  499.   /* try to create the .INI file key */
  500.   lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,
  501.                               "SOFTWARE\\Public Domain\\Blat",
  502.                               0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL, &hKey1,&dwDisposition
  503.                             );
  504.  
  505.   /* if we failed, note it, and leave */
  506.   if (lRetCode != ERROR_SUCCESS)
  507.   {
  508.     if( ! quiet ) printf ("Error in creating blat key in the registry\n");
  509.     return 10;
  510.   }
  511.  
  512.   /* try to set a section value */
  513.   lRetCode = RegSetValueEx( hKey1,"SMTP server",0,REG_SZ, (BYTE *) &SMTPHost[0], (strlen(SMTPHost)+1));
  514.  
  515.   /* if we failed, note it, and leave */
  516.   if (lRetCode != ERROR_SUCCESS)
  517.   {
  518.     if( ! quiet ) printf ( "Error in setting SMTP server value in the registry\n");
  519.     return 11;
  520.   }
  521.   
  522.   /* try to set another section value */
  523.   lRetCode = RegSetValueEx( hKey1,"Sender",0,REG_SZ, (BYTE *) &Sender[0], (strlen(Sender)+1));
  524.  
  525.   /* if we failed, note it, and leave */
  526.   if (lRetCode != ERROR_SUCCESS)
  527.   {
  528.    if( ! quiet ) printf ( "Error in setting sender address value in the registry\n");
  529.     return 11;
  530.   }
  531.   
  532.   return 0;
  533. }
  534.  
  535. // get the registry entries for this program 
  536. int GetRegEntry( void )
  537. {
  538.   HKEY  hKey1;
  539.   DWORD  dwType;
  540.   DWORD  dwBytesRead;
  541.   LONG   lRetCode;
  542.  
  543.   // open the registry key in read mode
  544.   lRetCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  545.                            "SOFTWARE\\Public Domain\\Blat",
  546.                            0, KEY_READ, &hKey1
  547.                          );
  548.   if( lRetCode != ERROR_SUCCESS )
  549.   {
  550.      if( ! quiet ) printf( "Failed to open registry key for Blat\n" );
  551.      return 12;
  552.   }
  553.   // set the size of the buffer to contain the data returned from the registry
  554.   // thanks to Beverly Brown "beverly@datacube.com" and "chick@cyberspace.com" for spotting it...
  555.   dwBytesRead=SERVER_SIZE;
  556.   // read the value of the SMTP server entry
  557.   lRetCode = RegQueryValueEx( hKey1, "SMTP server", NULL , &dwType, (BYTE *) &SMTPHost, &dwBytesRead); 
  558.   // if we failed, note it, and leave
  559.   if( lRetCode != ERROR_SUCCESS )
  560.   {
  561.     if( ! quiet ) printf( "Failed to read SMTP server value from the registry\n" );
  562.     return 12;
  563.   }
  564.  
  565.   dwBytesRead=SENDER_SIZE;
  566.   // read the value of the SMTP server entry
  567.   lRetCode = RegQueryValueEx( hKey1, "Sender", NULL , &dwType, (BYTE *) &Sender, &dwBytesRead); 
  568.   // if we failed, note it, and leave
  569.   if( lRetCode != ERROR_SUCCESS )
  570.   {
  571.     if( ! quiet ) printf( "Failed to read senders user name from the registry\n" );
  572.     return 12;
  573.   }
  574.  
  575.  return 0;
  576. }
  577.  
  578. // MIME Quoted-Printable Content-Transfer-Encoding
  579. #define MimeHexChar "0123456789ABCDEF"; 
  580. void ConvertToQuotedPrintable(char ThisChar, int * CurrPos, char * buffer) {
  581. int ThisValue;
  582. div_t result;
  583. // char buffer[8];
  584. char HexTable[17] = MimeHexChar;
  585.     
  586.     ThisValue = (256 + (unsigned int) ThisChar) % 256; 
  587.  
  588.     if    (ThisValue == 13) {
  589.         sprintf( buffer, "%s", "\0" );
  590.         return;
  591.     }
  592.     else if    (ThisValue == 10) {
  593.         sprintf( buffer, "%s", "\r\n" );
  594.         (*CurrPos) = 0;
  595.         return;
  596.     }
  597.     else if ((ThisValue < 33) | 
  598.             (ThisValue == 61) | 
  599.             (ThisValue > 126)) {
  600.         result = div(ThisValue,16); 
  601.         buffer[0] = '=';
  602.         (*CurrPos)++;
  603.         buffer[1] = HexTable[result.quot];
  604.         (*CurrPos)++;
  605.         buffer[2] = HexTable[result.rem];
  606.          (*CurrPos)++;
  607.         buffer[3] = '\0';
  608.     }
  609.     else {
  610.         buffer[0] = ThisChar;
  611.         (*CurrPos)++;
  612.         buffer[1] = '\0';
  613.     } 
  614.  
  615.        if (*CurrPos > 71) {
  616.         strcat(buffer, "=\r\n");     /* Add soft line break */
  617.         (*CurrPos) = 0;
  618.     }
  619. }
  620.  
  621.  
  622. int main( int argc,        /* Number of strings in array argv          */
  623.            char *argv[],    /* Array of command-line argument strings   */
  624.            char **envp )    /* Array of environment variable strings    */
  625. {
  626.  int next_arg=2;
  627.  int impersonating = 0;
  628.  int penguin = 0;
  629.  int i, j;
  630.  int retcode;
  631.  char tempdir[MAX_PATH+1];
  632.  char tempfile[MAX_PATH+1];
  633.  HANDLE fileh;
  634.  FILE *tf;
  635.  int hours, minutes;
  636.  OFSTRUCT of;
  637.  
  638.  
  639.  // by default Blat is very noisy!
  640.  quiet = 0;
  641.  
  642. // by default Blat does not use mime Quoted-Printable Content-Transfer-Encoding!
  643.  mime = 0;
  644.  
  645.  // no tempfile so far...
  646.  tempfile[0] = '\0';
  647.  
  648.  if(argc<2)
  649.  {
  650.   // must have at least file name to send
  651.   for(i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
  652.   return 1;
  653.  }
  654.  
  655.  for( i=1; i < argc; i++ ) {
  656.   if( lstrcmpi( "-q",argv[i] ) == 0 ) quiet = 1;
  657.   if( lstrcmpi( "-mime",argv[i] ) == 0 ) mime = 1;
  658.  }
  659.  
  660.  // get file name from argv[1]
  661.  char *filename=argv[1];
  662.  
  663.  Sender[0] = '\0';
  664.  SMTPHost[0] = '\0';
  665.  
  666.  GetRegEntry();
  667.  
  668.  senderid  = Sender;
  669.  loginname = Sender;
  670.         
  671.  // thanks to Beverly Brown "beverly@datacube.com" for
  672.  // fixing the argument parsing, I "fixed" the brackets
  673.  // to conform approximately to our "style"  :-)
  674.  // Starts here
  675.  for(next_arg=1;next_arg < argc;next_arg++)
  676.  {
  677.     if(lstrcmpi("-h",argv[next_arg])==0)
  678.     {
  679.      if( ! quiet ) for(int i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
  680.      return 1;
  681.     }
  682.  
  683.           // is argv[2] "-install"? If so, indicate error and return
  684.     else if(lstrcmpi("-install",argv[next_arg])==0)
  685.     {
  686.        if((argc == 3) || (argc == 4)) 
  687.              {
  688.             strcpy( SMTPHost, argv[++next_arg] );
  689.              if(argc == 4) 
  690.                  strcpy( Sender, argv[++next_arg] );
  691.             else
  692.                 strcpy( Sender, "" );
  693.              if( CreateRegEntry() == 0 ) 
  694.                  {
  695.                    if( ! quiet ) printf("\nSMTP server set to %s\n", SMTPHost );
  696.                   return 0;
  697.                  }
  698.              }
  699.        else
  700.           {
  701.            if( ! quiet )
  702.             printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username");
  703.              return 6;
  704.           }
  705.     }
  706.  
  707.         // is argv[2] "-s"? If so, argv[3] is the subject
  708.     else if(lstrcmpi("-s",argv[next_arg])==0)
  709.     {
  710.      subject=argv[++next_arg];
  711.     }
  712.  
  713.        // is argv[2] "-c"? If so, argv[3] is the carbon-copy list
  714.     else if(lstrcmpi("-c",argv[next_arg])==0)
  715.     {
  716.      cc_list=argv[++next_arg];
  717.     }
  718.  
  719.        // is argv[2] "-b"? If so, argv[3] is the blind carbon-copy list
  720.     else if(lstrcmpi("-b",argv[next_arg])==0)
  721.     {
  722.      bcc_list=argv[++next_arg];
  723.     }
  724.  
  725.         // is next argv "-t"? If so, succeeding argv is the destination
  726.     else if(lstrcmpi("-t",argv[next_arg])==0)
  727.     {
  728.      destination=argv[++next_arg];
  729.     }
  730.  
  731.     // is next argv "-server"? If so, succeeding argv is the SMTPHost    
  732.     else if(lstrcmpi("-server",argv[next_arg])==0)
  733.     {
  734.      strcpy(SMTPHost,argv[++next_arg]);
  735.     }
  736.  
  737.      //is next argv '-f'? If so, succeeding argv is the loginname
  738.     else if(lstrcmp("-f",argv[next_arg])==0)
  739.       loginname=argv[++next_arg];
  740.  
  741.     else if(lstrcmp("-penguin",argv[next_arg])==0)
  742.     {
  743.      penguin = 1;
  744.     }
  745.     
  746.     // if next arg is a '-mime' just increase and continue looking
  747.     // we have already dealt with -mime at the beggining
  748.     else if(lstrcmp("-mime",argv[next_arg])==0)
  749.     {
  750.      next_arg++;
  751.     }
  752.     
  753.     // if next arg is a '-q' just increase and continue looking
  754.     // we have already dealt with -q at the beggining
  755.     else if(lstrcmp("-q",argv[next_arg])==0)
  756.     {
  757.      next_arg++;
  758.     }
  759.  
  760.     //is next argv '-i'? If so, succeeding argv is the sender id
  761.     else if(lstrcmp("-i",argv[next_arg])==0)
  762.     {
  763.      senderid=argv[++next_arg];
  764.      impersonating = 1;
  765.     }
  766.     else if(next_arg == 1) 
  767.     {
  768.       if (lstrcmp(filename, "-") != 0)
  769.      {
  770.       if( lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST) == HFILE_ERROR )
  771.       {
  772.        if( ! quiet ) cout<<filename<<" does not exist\n";        
  773.         return 2;
  774.       }
  775.      }
  776.     } 
  777.     else 
  778.     {
  779.      if( ! quiet )
  780.       for(i=0;i<NMLINES;i++)
  781.         cout<<usage[i]<<'\n';
  782.      return 1;
  783.     }
  784.  }
  785.  
  786.     // if we are not impersonating loginname is the same as the sender
  787.     if( ! impersonating )
  788.           senderid = loginname;
  789.  
  790.       // fixing the argument parsing
  791.       // Ends here
  792.  
  793.     if ((SMTPHost[0]=='\0')||(loginname[0]=='\0'))
  794.     {
  795.      if( ! quiet )
  796.      {
  797.       printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username\n");
  798.       printf( "or use '-server <server name>' and '-f <user name>'\n");
  799.       printf( "aborting, nothing sent\n" );
  800.      }
  801.      return 12;
  802.     }
  803.     
  804.     // make sure filename exists, get full pathname
  805.     if (lstrcmp(filename, "-") != 0)
  806.      if(lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST)==HFILE_ERROR)
  807.      {
  808.       if( ! quiet ) cout<<filename<<" does not exist\n";        
  809.       return 2;
  810.      }
  811.  
  812.     // build temporary recipients list for parsing the "To:" line
  813.     char *temp = new char [ strlen(destination) + strlen(cc_list) + strlen(bcc_list) + 4 ];
  814.     // build the recipients list
  815.     Recipients = new char [ strlen(destination) + strlen(cc_list) + strlen(bcc_list) + 4 ];
  816.     
  817.     // Parse the "To:" line
  818.     for (i = j = 0; i < (int) strlen(destination); i++)
  819.     {
  820.       // strip white space
  821.       while (destination[i]==' ')
  822.         i++;
  823.       // look for comments in brackets, and omit
  824.       if (destination[i]=='(')
  825.       {
  826.         while (destination[i]!=')')
  827.           i++;
  828.         i++;
  829.       }      
  830.         // look for comments in quotes, and omit
  831.         if (destination[i]=='\'')
  832.       {
  833.       i++;
  834.         while (destination[i]!='\'')
  835.           i++;
  836.         i++;
  837.       }      
  838.       
  839.       temp[j++] = destination[i];
  840.     }
  841.     temp[j] = '\0';               // End of list added! 
  842.     strcpy( Recipients, temp);
  843.  
  844.     // Parse the "Cc:" line
  845.     for (i = j = 0; i < (int) strlen(cc_list); i++)
  846.     {
  847.      // strip white space
  848.      while (cc_list[i]==' ') i++;
  849.      // look for comments in brackets, and omit
  850.      if (cc_list[i]=='(')
  851.      {
  852.       while (cc_list[i]!=')') i++;
  853.       i++;
  854.      }      
  855.        // look for comments in quotes, and omit
  856.        if (cc_list[i]=='\'')
  857.      {
  858.       i++;
  859.       while (cc_list[i]!='\'') i++;
  860.       i++;
  861.      }      
  862.      temp[j++] = cc_list[i];
  863.     }
  864.     temp[j] = '\0';               // End of list added! 
  865.     if( strlen(cc_list) > 0 )
  866.     {
  867.      strcat(Recipients, "," );
  868.      strcat(Recipients, temp);
  869.     }
  870.  
  871.     // Parse the "Bcc:" line
  872.     for (i = j = 0; i < (int) strlen(bcc_list); i++)
  873.     {
  874.      // strip white space
  875.      while (bcc_list[i]==' ') i++;
  876.      // look for comments in brackets, and omit
  877.      if (bcc_list[i]=='(')
  878.      {
  879.       while (bcc_list[i]!=')') i++;
  880.       i++;
  881.      }      
  882.        // look for comments in quotes, and omit
  883.        if (bcc_list[i]=='\'')
  884.      {
  885.       i++;
  886.       while (bcc_list[i]!='\'') i++;
  887.       i++;
  888.      }      
  889.      temp[j++] = bcc_list[i];
  890.     }
  891.     temp[j] = '\0';               // End of list added! 
  892.     if( strlen(bcc_list) > 0 )
  893.     {
  894.      strcat(Recipients, "," );
  895.      strcat(Recipients, temp);
  896.     }
  897.    
  898.  
  899.     // create a header for the message
  900.     char tmpstr[256];
  901.     char header[2048];
  902.     int  headerlen;
  903.     SYSTEMTIME curtime;
  904.     TIME_ZONE_INFORMATION tzinfo;
  905.     char * days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  906.     char * months[] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  907.     DWORD retval;
  908.  
  909.     GetLocalTime( &curtime );
  910.     retval = GetTimeZoneInformation( &tzinfo );
  911.     hours = (int) tzinfo.Bias / 60;
  912.     minutes = (int) tzinfo.Bias % 60;
  913.     if( retval == TIME_ZONE_ID_STANDARD ) 
  914.     {
  915.      hours += (int) tzinfo.StandardBias / 60;
  916.      minutes += (int) tzinfo.StandardBias % 60;
  917.     }
  918.     else
  919.       {
  920.      hours += (int) tzinfo.DaylightBias / 60;
  921.      minutes += (int) tzinfo.DaylightBias % 60;
  922.     }
  923.     
  924.     // rfc1036 & rfc822 acceptable format
  925.     // Mon, 29 Jun 94 02:15:23 GMT
  926.     sprintf (tmpstr, "Date: %s, %.2d %s %.2d %.2d:%.2d:%.2d ",
  927.       days[curtime.wDayOfWeek],
  928.       curtime.wDay,
  929.       months[curtime.wMonth - 1],
  930.       curtime.wYear,
  931.       curtime.wHour,
  932.       curtime.wMinute,
  933.       curtime.wSecond);
  934.     strcpy( header, tmpstr );
  935.  
  936.     sprintf( tmpstr, "%+03d%02d", -hours, -minutes );
  937.     //for(i=0;i<32;i++)
  938.     //{
  939.     // if( retval == TIME_ZONE_ID_STANDARD ) tmpstr[i] = (char) tzinfo.StandardName[i];
  940.     // else tmpstr[i] = (char) tzinfo.DaylightName[i];
  941.     //}
  942.     strcat( header, tmpstr );
  943.     strcat( header, "\r\n" );
  944.     sprintf( tmpstr, "From: %s\r\n", senderid );
  945.     strcat( header, tmpstr );
  946.     if( impersonating )
  947.     {
  948.      sprintf( tmpstr, "Sender: %s\r\n", loginname );
  949.      strcat( header, tmpstr );
  950.     if (!(penguin == 1))
  951.      {
  952.      sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
  953.      strcat( header, tmpstr );
  954.      }
  955.     }
  956.     if( *subject )
  957.     {
  958.      sprintf( tmpstr, "Subject: %s\r\n", subject );
  959.      strcat( header, tmpstr );
  960.     }
  961.     else
  962.     {
  963.      if (!(penguin == 1))
  964.      {
  965.       if (lstrcmp(filename, "-") == 0)
  966.        sprintf( tmpstr, "Subject: Contents of console input\r\n", filename );
  967.       else
  968.        sprintf( tmpstr, "Subject: Contents of file: %s\r\n", filename );
  969.       strcat( header, tmpstr );
  970.      }
  971.     }
  972.     
  973.     sprintf( tmpstr, "To: %s\r\n", destination );
  974.     strcat( header, tmpstr );
  975.     if( *cc_list )
  976.     {
  977.      // Add line for the Carbon Copies
  978.      sprintf( tmpstr, "Cc: %s\r\n", cc_list );
  979.      strcat( header, tmpstr );
  980.     }
  981.  
  982.     if ( mime ) 
  983.     {
  984.      // Indicate MIME version and type 
  985.      sprintf( tmpstr, "MIME-Version: 1.0\r\n", cc_list );
  986.      strcat( header, tmpstr );
  987.      sprintf( tmpstr, "Content-Type: text/plain; charset=ISO-8859-1\r\n", cc_list );
  988.      strcat( header, tmpstr );
  989.      sprintf( tmpstr, "Content-Transfer-Encoding: quoted-printable\r\n", cc_list );
  990.      strcat( header, tmpstr );
  991.     }
  992.  
  993.     strcat( header, "X-Mailer: <WinNT's Blat ver 1.5>\r\n" );
  994.     
  995.     if (!(penguin == 1))
  996.         strcat( header, "\r\n" );
  997.  
  998.     headerlen = strlen( header );
  999.  
  1000.     // if reading from the console, read everything into a temporary file first
  1001.     if (lstrcmp(filename, "-") == 0)
  1002.     {
  1003.      // create a unique temporary file name
  1004.      GetTempPath( MAX_PATH, tempdir );
  1005.      GetTempFileName( tempdir, "blt", 0, tempfile );
  1006.  
  1007.      // open the file in write mode
  1008.      tf = fopen(tempfile,"w");
  1009.      if( tf==NULL )
  1010.      {
  1011.       if( ! quiet ) cout<<"error opening temporary file "<<filename<<", aborting\n";        
  1012.       delete [] Recipients;
  1013.       return 13;
  1014.      }
  1015.  
  1016.      do
  1017.      {
  1018.       i = getc( stdin );
  1019.       putc( i, tf );
  1020.      }
  1021.      while( i != EOF );
  1022.  
  1023.      fclose( tf );
  1024.      filename = tempfile;
  1025.     }
  1026.  
  1027.     //get the text of the file into a string buffer
  1028.     if((fileh=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  1029.                          FILE_FLAG_SEQUENTIAL_SCAN,NULL))==INVALID_HANDLE_VALUE)
  1030.     {
  1031.      if( ! quiet ) cout<<"error reading "<<filename<<", aborting\n";        
  1032.      delete [] Recipients;
  1033.      return 3;
  1034.     }
  1035.     if(GetFileType(fileh)!=FILE_TYPE_DISK)
  1036.     {
  1037.      if( ! quiet ) cout<<"Sorry, I can only mail messages from disk files...\n";        
  1038.      delete [] Recipients;
  1039.      return 4;
  1040.     }
  1041.     DWORD filesize = GetFileSize( fileh,NULL );
  1042.     char *buffer = new char[(3*(filesize+filesize/72))+headerlen+1];
  1043.     char *filebuffer = new char[filesize+1];
  1044.     char *tmpptr;
  1045.     char *q; 
  1046.     char *p; 
  1047.  
  1048.     // put the header at the top...
  1049.     strcpy( buffer, header );
  1050.     // point to the end of the header
  1051.     tmpptr = buffer + headerlen;
  1052.     // and put the whole file there
  1053.     DWORD dummy;
  1054.     if(!ReadFile(fileh,filebuffer,filesize,&dummy,NULL))
  1055.     {
  1056.      if( ! quiet ) cout<<"error reading "<<filename<<", aborting\n";
  1057.      CloseHandle(fileh);
  1058.      delete [] buffer;        
  1059.      delete [] filebuffer;        
  1060.      delete [] Recipients;
  1061.      return 5;
  1062.     }
  1063.     CloseHandle(fileh);
  1064.  
  1065.        q = filebuffer + filesize; 
  1066.     (*q) = '\0'; 
  1067.  
  1068.     // MIME Quoted-Printable Content-Transfer-Encoding
  1069.     if ( ! mime) 
  1070.      strcpy( tmpptr, filebuffer );
  1071.     else {
  1072.      int PosValue = 0; 
  1073.      int *Pos; 
  1074.      char workbuf [8]; 
  1075.      Pos = &PosValue; 
  1076.      p = filebuffer; 
  1077.      while (p < q) {
  1078.       ConvertToQuotedPrintable(*p,Pos, workbuf);
  1079.       strcat(tmpptr,workbuf); 
  1080.       *p++;
  1081.      } 
  1082.     }
  1083.  
  1084.     // delete the temporary file if it has been used
  1085.     if ( *tempfile ) remove( tempfile );
  1086.         
  1087.     // make some noise about what we are doing
  1088.     if( ! quiet )
  1089.     {    
  1090.      cout<<"Sending "<<filename<<" to "<< (lstrlen(Recipients) ? Recipients : "<unspecified>")<<'\n';
  1091.      if(lstrlen(subject)) cout<<"Subject:"<<subject<<'\n';
  1092.      if(lstrlen(loginname)) cout<<"Login name is "<<loginname<<'\n';
  1093.     }
  1094.  
  1095.   // send the message to the SMTP server!
  1096.   retcode = prepare_smtp_message( loginname, Recipients );
  1097.   if( !retcode )
  1098.   {
  1099.    retcode = send_smtp_edit_data( buffer ); 
  1100.    if( !retcode )
  1101.     finish_smtp_message();
  1102.    close_smtp_socket();
  1103.   }
  1104.  
  1105.   delete [] buffer;
  1106.   delete [] filebuffer;        
  1107.   delete [] Recipients;
  1108.   return (retcode);
  1109. }
  1110.  
  1111.